package com.weipai.springboot.module.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.weipai.springboot.enums.DemandStatus;
import com.weipai.springboot.enums.OrderStatus;
import com.weipai.springboot.enums.RetCode;
import com.weipai.springboot.model.*;
import com.weipai.springboot.model.api.Response;
import com.weipai.springboot.module.dao.*;
import com.weipai.springboot.module.mapper.CustomerGiftMapper;
import com.weipai.springboot.module.mapper.CustomerMapper;
import com.weipai.springboot.module.service.PayService;
import com.weipai.springboot.module.util.DateUtils;
import com.weipai.springboot.module.util.wxPayUtil.HttpRequest;
import com.weipai.springboot.module.util.SessionUserUtil;
import com.weipai.springboot.module.util.wxPayUtil.WXPayUtil;
import com.weipai.springboot.util.*;
import com.weipai.springboot.util.unionSdk.DemoBase;
import com.weipai.springboot.util.unionSdk.AcpService;
import com.weipai.springboot.util.unionSdk.LogUtil;
import com.weipai.springboot.util.unionSdk.SDKConfig;
import com.weipai.springboot.util.unionSdk.SDKConstants;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author songmengqiang
 * @create 2018-08-28 14:12
 **/
@Service
public class PayServiceImpl implements PayService {

    private static final Logger log = LoggerFactory.getLogger(PayServiceImpl.class);

    @Autowired
    private PayDao payDao;
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private WxPayDao wxPayDao;
    @Autowired
    private CustomerDao customerDao;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    SessionUserUtil sessionUserUtil;
    @Autowired
    private ReputationHistoryDao reputationHistoryDao;
    @Autowired
    private DemandDao demandDao;
    @Autowired
    private CustomerGiftMapper customerGiftMapper;


    @Override
    public Response getPayModeList() {
        List<PayMode> payModeList = payDao.getPayModeList();
        Response response = new Response();
        response.setCode(RetCode.SUCCESS);
        response.put("payModeList", payModeList);
        return response;
    }

    //支付宝支付
    @Override
    public Response aliPay(String orderNumber, int payment, String source) {
        Map<String, Object> order;
        if ("1".equals(source)) {
            order = orderDao.getOrderInfoByOrderNumber(orderNumber);
        } else {
            order = demandDao.getDemandInfoByDemandNumber(orderNumber);
        }
        Response response = new Response();
        //验证订单是否填写了地址
        getAddress(orderNumber);
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody("aliPay");
        model.setSubject("订单支付");
        model.setOutTradeNo(orderNumber);
        model.setTimeoutExpress("30m");
        BigDecimal newPrice = new BigDecimal(Integer.parseInt(order.get("realPay").toString()));
        //换成分计算
        model.setTotalAmount(String.valueOf(newPrice.divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_DOWN)));
        model.setProductCode("QUICK_MSECURITY_PAY");
        String sign = AliPayUtil.creatSign(model);
        if (sign != null) {
            response.setCode(RetCode.SUCCESS);
            response.put("data", sign);
        } else {
            response.setCode(RetCode.REQUEST_ERROR);
        }
        return response;
    }


    //微信jspi支付
    public Response wxPayJsapi(HttpServletRequest request, String orderNumber, Integer payment, String spbillCreateIp, String source, String customerId) {
        Response response = new Response();
//        log.info("微信jsapi开始----------------------");
        getAddress(orderNumber);
        Map<String, Object> order;
        if ("1".equals(source)) {
            order = orderDao.getOrderInfoByOrderNumber(orderNumber);
        } else {
            order = demandDao.getDemandInfoByDemandNumber(orderNumber);
        }
        Customer customer = customerMapper.getCustomerById(customerId);

        try {
            WxPayMessage wxPayMessage = new WxPayMessage();
            wxPayMessage.setBody("微信支付");
            Integer wxAmount = Integer.parseInt(order.get("realPay").toString());
            wxPayMessage.setTotalFee(wxAmount);
            wxPayMessage.setSpbillCreateIp(wxPayMessage.getIpAddress(request));
            if (customer.getWxOppenid() != null && !"".equals(customer.getWxOppenid())) {
//                //页面获取openId接口
//                String getopenid_url = "https://api.weixin.qq.com/sns/oauth2/access_token";
//                String param = "appid=" + wxPayMessage.getAppId() + "&secret=" + wxPayMessage.getSecret() + "&code=" + code + "&grant_type=authorization_code";
//                //向微信服务器发送get请求获取openIdStr
//                String openIdStr = HttpRequest.sendGet(getopenid_url, param);
//                JSONObject json = JSONObject.fromObject(openIdStr);//转成Json格式
//                String openId = json.getString("openid");//获取openId
                //拼接统一下单地址参数
                Map<String, String> paraMap = new HashMap<String, String>();
                paraMap.put("appid", wxPayMessage.getAppId());
                paraMap.put("body", wxPayMessage.getBody());
                paraMap.put("mch_id", wxPayMessage.getMchId());
                paraMap.put("nonce_str", wxPayMessage.getNonceStr());
                //paraMap.put("openid", customer.getWxOppenid());
                paraMap.put("openid", customer.getWxOppenid());
                paraMap.put("out_trade_no", orderNumber);//订单号
                wxPayMessage.setDetail("工造易采");
                wxPayMessage.setOutTradeNo(orderNumber);
//                paraMap.put("spbill_create_ip", wxPayMessage.getSpbillCreateIp());
                paraMap.put("spbill_create_ip", spbillCreateIp);
                paraMap.put("total_fee", Integer.toString(wxPayMessage.getTotalFee()));
//                paraMap.put("total_fee", "1");
                paraMap.put("trade_type", "JSAPI");
                paraMap.put("fee_type", wxPayMessage.getFeeType());
                paraMap.putIfAbsent("sign_type", wxPayMessage.getSignType());
                paraMap.put("detail", wxPayMessage.getDetail());
                paraMap.put("notify_url", PropUtils.getString("Notify_Url"));
                String sign = WXPayUtil.generateSignature(paraMap, wxPayMessage.getKey());
                paraMap.put("sign", sign);
                String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
                log.info("xml=======================" + xml);
                // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
                String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
                String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
                log.info("xmlStr=======================" + xmlStr);
                //以下内容是返回前端页面的json数据
                String prepay_id = "";//预支付id
                if (xmlStr.indexOf("SUCCESS") != -1) {
                    Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
                    prepay_id = (String) map.get("prepay_id");
                    log.info("prepay_id=======================" + prepay_id);
                }
                Map<String, String> payMap = new HashMap<String, String>();
                payMap.put("appId", wxPayMessage.getAppId());
                payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
                payMap.put("nonceStr", WXPayUtil.generateNonceStr());
                payMap.put("signType", "MD5");
                payMap.put("package", "prepay_id=" + prepay_id);
                String paySign = WXPayUtil.generateSignature(payMap, wxPayMessage.getKey());
                payMap.put("pg", prepay_id);
                payMap.put("paySign", paySign);
//                log.info("返回数据=====================" + payMap);
                response.put("data", payMap);
//                log.info("微信jsapi结束----------------------");
                response.setCode(RetCode.SUCCESS);
                return response;
            } else {
                response.setCode(RetCode.REQUEST_ERROR);
                return response;
            }
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(RetCode.REQUEST_ERROR);
            return response;
        }

    }


    //微信支付
    @Override
    public Response wxPay(String orderNumber, int payment, String spbillCreateIp, String source) {
        Response response = new Response();
        getAddress(orderNumber);
        Map<String, Object> order;
        if ("1".equals(source)) {
            order = orderDao.getOrderInfoByOrderNumber(orderNumber);
        } else {
            order = demandDao.getDemandInfoByDemandNumber(orderNumber);
        }
        try {
            WxPayMessage wxPayMessage = new WxPayMessage();
            wxPayMessage.setBody("微信支付");
            Integer wxAmount = Integer.parseInt(order.get("realPay").toString());
            wxPayMessage.setTotalFee(wxAmount);
            wxPayMessage.setSpbillCreateIp(spbillCreateIp);
            Map<String, String> paraMap = new HashMap<String, String>();
            paraMap.put("appid", wxPayMessage.getAppIdApp());
            paraMap.put("body", wxPayMessage.getBody());
            paraMap.put("mch_id", wxPayMessage.getMchId());
            paraMap.put("nonce_str", wxPayMessage.getNonceStr());
            paraMap.put("notify_url", PropUtils.getString("Notify_Url"));
            paraMap.put("out_trade_no", orderNumber);//订单号
            wxPayMessage.setDetail("工造易采");
            wxPayMessage.setOutTradeNo(orderNumber);
            paraMap.put("spbill_create_ip", spbillCreateIp);
            paraMap.put("total_fee", Integer.toString(wxPayMessage.getTotalFee()));
            paraMap.put("trade_type", wxPayMessage.getTradeType());
            paraMap.put("fee_type", wxPayMessage.getFeeType());
            paraMap.putIfAbsent("sign_type", wxPayMessage.getSignType());
            paraMap.put("detail", wxPayMessage.getDetail());
            String sign = WXPayUtil.generateSignature(paraMap, wxPayMessage.getKey());
            paraMap.put("sign", sign);
            String xml = WXPayUtil.mapToXml(paraMap);//将所有参数(map)转xml格式
//            log.info("xml=======================" + xml);
            // 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
            String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
//            log.info("xmlStr=======================" + xmlStr);
            //以下内容是返回前端页面的json数据
            String prepay_id = "";//预支付id
            if (xmlStr.indexOf("SUCCESS") != -1) {
                Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
                prepay_id = (String) map.get("prepay_id");
//                log.info("prepay_id=======================" + prepay_id);
            }
            Map<String, String> payMap = new HashMap<String, String>();
            payMap.put("appid", wxPayMessage.getAppIdApp());
            payMap.put("partnerid", wxPayMessage.getMchId());
            payMap.put("prepayid", prepay_id);
            payMap.put("package", "Sign=WXPay");
            payMap.put("noncestr", WXPayUtil.generateNonceStr());
            payMap.put("timestamp", WXPayUtil.getCurrentTimestamp() + "");
            String paySign = WXPayUtil.generateSignature(payMap, wxPayMessage.getKey());
            payMap.put("sign", paySign);
//            log.info("返回数据=====================" + payMap);
            response.put("data", payMap);
//            log.info("微信jsapi结束----------------------");
            response.setCode(RetCode.SUCCESS);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setCode(RetCode.REQUEST_ERROR);
            return response;
        }
    }

    //微信pc扫码支付
    @Override
    public Response wxEwmPay(String orderNumber, Integer payment, String spbillCreateIp, String source, HttpServletResponse httpRespon) {
        Response response = new Response();
//        System.err.println("==========进入微信pc扫码支付方法==================");
        try {
            getAddress(orderNumber);
            Map<String, Object> order;
            if ("1".equals(source)) {
                order = orderDao.getOrderInfoByOrderNumber(orderNumber);
            } else {
                order = demandDao.getDemandInfoByDemandNumber(orderNumber);
            }

            SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
            packageParams.put("appid", PropUtils.getString("appId"));
            packageParams.put("mch_id", PropUtils.getString("mchId"));
            packageParams.put("nonce_str", UUID.randomUUID().toString().toUpperCase().replaceAll("-", ""));
            packageParams.put("body", "微信扫码支付");  //（调整为自己的名称）
            packageParams.put("out_trade_no", orderNumber);
            packageParams.put("total_fee", order.get("realPay").toString()); //价格的单位为分
            packageParams.put("spbill_create_ip", spbillCreateIp);
            packageParams.put("notify_url", PropUtils.getString("wxEwmPayNotify_Url"));
            packageParams.put("trade_type", "NATIVE");

            String sign = PayToolUtil.createSign("UTF-8", packageParams, PropUtils.getString("key"));
            packageParams.put("sign", sign);

            String requestXML = PayToolUtil.getRequestXml(packageParams);
            System.out.println(requestXML);

            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String resXml = HttpUtil.postData(url, requestXML);

            Map map = XMLUtil.doXMLParse(resXml);


            String result_code = (String) map.get("result_code");
//            System.out.println("==========================result_code====================" + result_code);
            if ("SUCCESS".equals(result_code)) {
                String urlCode = (String) map.get("code_url");
                response.setCode(RetCode.SUCCESS);
//                System.out.println("================urlCode=================================" + urlCode);
                response.setData(urlCode);
                /*BufferedImage image = PayUtil.getQRCodeImge(urlCode);

                httpRespon.setContentType("image/jpeg");
                httpRespon.setHeader("Pragma","no-cache");
                httpRespon.setHeader("Cache-Control","no-cache");
                httpRespon.setIntHeader("Expires",-1);
                ImageIO.write(image, "JPEG", httpRespon.getOutputStream());*/
                return response;
            }
        } catch (Exception e) {
            log.error("wxEwmPay error:{}", e);
            response.setCode(RetCode.REQUEST_ERROR);
        }
        return response;
    }

    //微信pc扫码支付回调
    @Override
    public void wxEwmPayNotify(HttpServletRequest request, HttpServletResponse response) {
        System.err.println("==========进入微信pc扫码支付回调方法==================");
        BufferedOutputStream out = null;
        try {
            //读取参数
            InputStream inputStream;
            StringBuffer sb = new StringBuffer();
            inputStream = request.getInputStream();
            String s;
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = in.readLine()) != null) {
                sb.append(s);
            }
            in.close();
            inputStream.close();

            //解析xml成map
            Map<String, String> m = new HashMap<String, String>();
            m = XMLUtil.doXMLParse(sb.toString());

            //过滤空 设置 TreeMap
            SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
            Iterator it = m.keySet().iterator();
            while (it.hasNext()) {
                String parameter = (String) it.next();
                String parameterValue = m.get(parameter);

                String v = "";
                if (null != parameterValue) {
                    v = parameterValue.trim();
                }
                packageParams.put(parameter, v);
            }
            //判断签名是否正确
            if (PayToolUtil.isTenpaySign("UTF-8", packageParams, PropUtils.getString("key"))) {
                System.err.println("==========微信签名验签成功==================");
                String resXml = "";
                if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
                    String out_trade_no = (String) packageParams.get("out_trade_no");
                    System.err.println("==========开始处理业务逻辑==================");
                    //处理逻辑
                    callBack(out_trade_no, 2);

                    //通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";

                } else {
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
                }
                out = new BufferedOutputStream(
                        response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } else {
                log.error("wxEwmPayNotify sign fail orderNumber ={}");
            }
        } catch (Exception e) {
            log.error("wxEwmPayNotify error :{}", e);
        }
    }

    //支付宝扫码支付
    @Override
    public void aliEwmPay(String orderNumber, Integer payment, String source, HttpServletResponse httpRespon) {
        System.err.println("==========进入支付宝扫码支付==================");
        Map<String, Object> order;
        if ("1".equals(source)) {
            order = orderDao.getOrderInfoByOrderNumber(orderNumber);
        } else {
            order = demandDao.getDemandInfoByDemandNumber(orderNumber);
        }
        Response response2 = new Response();
        //验证订单是否填写了地址
        getAddress(orderNumber);

        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                PropUtils.getString("APP_ID"),
                PropUtils.getString("APP_PRIVATE_KEY"),
                "json",
                "UTF-8",
                PropUtils.getString("ALIPAY_PUBLIC_KEY"),
                "RSA2"); //获得初始化的AlipayClient
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
        alipayRequest.setReturnUrl("http://domain.com/CallBack/return_url.jsp");
        alipayRequest.setNotifyUrl(PropUtils.getString("NOTIFY_URL"));//在公共参数中设置回跳和通知地址

        //根据订单号查询订单信息
        Map<String, Object> maps = new HashMap<>();
        maps.put("out_trade_no", orderNumber);
        BigDecimal newPrice = new BigDecimal(Integer.parseInt(order.get("realPay").toString()));
        maps.put("total_amount", String.valueOf(newPrice.divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_DOWN)));
        maps.put("subject", "支付宝扫码订单支付");
        maps.put("product_code", "FAST_INSTANT_TRADE_PAY");
        maps.put("timeout_express", "30m");
        //把订单信息转换为json对象的字符串
        String postdata = JSONObject.fromObject(maps).toString();
        alipayRequest.setBizContent(postdata);

        String form = "";
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpRespon.setContentType("text/html;charset=" + "utf-8");
        try {
            httpRespon.getWriter().write(form);//直接将完整的表单html输出到页面
            httpRespon.getWriter().flush();
            httpRespon.getWriter().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Response timerWxEwmPay(String orderNumber) {
        Response response = new Response();
        Order order = orderDao.getOrderInfoByOrderNumber22(orderNumber);
        if (order != null) {
            if (order.getOrderStatus() == OrderStatus.UNDELIVERED.getStatus()) {
                response.setCode(RetCode.SUCCESS);
            } else {
                response.setCode(RetCode.REQUEST_ERROR);
            }
        } else {
            response.setCode(RetCode.NO_DATA);
        }
        return response;
    }


    //到付
    @Override
    public Response collectPay(String orderNumber, int payment, String source) {
        Response response = new Response();
        callBack(orderNumber, payment);
        response.setCode(RetCode.SUCCESS);
        return response;
    }

    //银联支付
    @Override
    public void unionPay(HttpServletResponse resp, String orderId, String txnAmt, String txnTime) {
        resp.setContentType("text/html; charset=" + DemoBase.encoding);
        //String merId = PropUtils.getString("mer_id");
        String merId = "898111948161251";
        Map<String, String> requestData = new HashMap<String, String>();

        /***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***/
        requestData.put("version", DemoBase.version);              //版本号，全渠道默认值
        requestData.put("encoding", DemoBase.encoding);              //字符集编码，可以使用UTF-8,GBK两种方式
        requestData.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法
        requestData.put("txnType", "01");                          //交易类型 ，01：消费
        requestData.put("txnSubType", "01");                          //交易子类型， 01：自助消费
        requestData.put("bizType", "000202");                      //业务类型，B2C网关支付，手机wap支付
        requestData.put("channelType", "07");                      //渠道类型，这个字段区分B2C网关支付和手机wap支付；07：PC,平板  08：手机

        /***商户接入参数***/
        requestData.put("merId", merId);    //商户号码，请改成自己申请的正式商户号或者open上注册得来的777测试商户号
        requestData.put("accessType", "0");//接入类型，0：直连商户 2:平台类商户接入
        requestData.put("orderId", orderId);  //商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则
        requestData.put("txnTime", txnTime); //订单发送时间，取系统时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效
        requestData.put("currencyCode", "156");//交易币种（境内商户一般是156 人民币）
        requestData.put("txnAmt", txnAmt);  //交易金额，单位分，不要带小数点
        //requestData.put("reqReserved", "透传字段"); //请求方保留域，如需使用请启用即可；透传字段（可以实现商户自定义参数的追踪）本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回，商户可以按需上传，长度为1-1024个字节。出现&={}[]符号时可能导致查询接口应答报文解析失败，建议尽量只传字母数字并使用|分割，或者可以最外层做一次base64编码(base64编码之后出现的等号不会导致解析失败可以不用管)。

        requestData.put("riskRateInfo", "{commodityName=测试商品名称}");

        //前台通知地址 （需设置为外网能访问 http https均可），支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址
        //如果想要实现过几秒中自动跳转回商户页面权限，需联系银联业务申请开通自动返回商户权限
        //异步通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
        requestData.put("frontUrl", DemoBase.frontUrl);

        //后台通知地址（需设置为【外网】能访问 http https均可），支付成功后银联会自动将异步通知报文post到商户上送的该地址，失败的交易银联不会发送后台通知
        //后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
        //注意:1.需设置为外网能访问，否则收不到通知    2.http https均可  3.收单后台通知后需要10秒内返回http200或302状态码
        //    4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200，那么银联会间隔一段时间再次发送。总共发送5次，每次的间隔时间为0,1,2,4分钟。
        //    5.后台通知地址如果上送了带有？的参数，例如：http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签，否则将会验签失败
        requestData.put("backUrl", DemoBase.backUrl);

        // 订单超时时间。
        // 超过此时间后，除网银交易外，其他交易银联系统会拒绝受理，提示超时。 跳转银行网银交易如果超时后交易成功，会自动退款，大约5个工作日金额返还到持卡人账户。
        // 此时间建议取支付时的北京时间加15分钟。
        // 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。
        requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));


        /**请求参数设置完毕，以下对请求参数进行签名并生成html表单，将表单写入浏览器跳转打开银联页面**/
        Map<String, String> submitFromData = AcpService.sign(requestData, DemoBase.encoding);  //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。

        String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //获取请求银联的前台地址：对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl
        String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData, DemoBase.encoding);   //生成自动跳转的Html表单

        LogUtil.writeLog("打印请求HTML，此为请求报文，为联调排查问题的依据：" + html);
        //将生成的html写到浏览器中完成自动跳转打开银联支付页面；这里调用signData之后，将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改，如果修改会导致验签不通过
        try {
            resp.getWriter().write(html);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //微信回调
    @Override
    public String wxPayNotify(HttpServletRequest request) {
        log.info("微信回调进入此方法-----------------------------------");
        try {
            InputStream inStream = request.getInputStream();
            int _buffer_size = 1024;
            if (inStream != null) {
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                byte[] tempBytes = new byte[_buffer_size];
                int count = -1;
                while ((count = inStream.read(tempBytes, 0, _buffer_size)) != -1) {
                    outStream.write(tempBytes, 0, count);
                }
                outStream.flush();
                outStream.close();
                //将流转换成字符串
                String result = new String(outStream.toByteArray(), "UTF-8");
                //将字符串转化成MAP格式数据
                Map<String, Object> resultMap = XMLUtil.doXMLParse(result);
                String out_trade_no = "";
                String sign = "";
                for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
                    if ("out_trade_no".equals(entry.getKey())) {
                        out_trade_no = (String) entry.getValue();
                    }
                    if ("sign".equals(entry.getKey())) {
                        sign = (String) entry.getValue();
                    }
                }
                //处理逻辑
                callBack(out_trade_no, 2);
            }
            //通知微信支付系统接收到信息
            return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        //如果失败返回错误，微信会再次发送支付信息
        return "fail";
    }

    //支付宝回调
    @Override
    public String aliPayNotify(HttpServletRequest request) {
        System.err.println("==========进入支付宝扫码支付回调==================");
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            /*try {
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
			} catch (UnsupportedEncodingException e) {
			    //TODO Auto-generated catch block
				e.printStackTrace();
			}*/
            /*System.err.println("name:"+name+"---"+"value:"+valueStr);*/
            params.put(name, valueStr);
        }
        /*切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
        boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)*/
        try {
            String aliPayPublicKey = PropUtils.getString("ALIPAY_PUBLIC_KEY");
            boolean flag = AlipaySignature.rsaCheckV1(params, aliPayPublicKey, "UTF-8", "RSA2");
            String orderNumber = request.getParameter("out_trade_no");
            if (flag) {
                System.err.println("==========支付宝回调验签成功，开始处理业务逻辑==================");
                //处理逻辑
                callBack(orderNumber, 1);
                return "success";
            } else {
                return "failure";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "failure";
    }

    //银联支付回调
    @Override
    public void unionPayNotify(HttpServletRequest req, HttpServletResponse resp) {
        LogUtil.writeLog("BackRcvResponse接收后台通知开始");

        String encoding = req.getParameter(SDKConstants.param_encoding);

        // 获取银联通知服务器发送的后台通知参数
        Map<String, String> reqParam = getAllRequestParam(req);

        LogUtil.printRequestLog(reqParam);


        //重要！验证签名前不要修改reqParam中的键值对的内容，否则会验签不过
        if (!AcpService.validate(reqParam, encoding)) {
            LogUtil.writeLog("验证签名结果[失败].");
            //验签失败，需解决验签问题
        } else {
            LogUtil.writeLog("验证签名结果[成功].");
            //【注：为了安全验签成功才应该写商户的成功处理逻辑】交易成功，更新商户订单状态
            //获取后台通知的数据，其他字段也可用类似方式获取
            String orderId = reqParam.get("orderId");
            String respCode = reqParam.get("respCode");
            //判断respCode=00、A6后，对涉及资金类的交易，请再发起查询接口查询，确定交易成功后更新数据库。
            if (respCode.equals("00") || respCode.equals("A6")) {
                //处理逻辑
                callBack(orderId, 3);
            }
        }
        LogUtil.writeLog("BackRcvResponse接收后台通知结束");
        //返回给银联服务器http 200  状态码
        try {
            resp.getWriter().print("ok");
        } catch (IOException e) {
            e.printStackTrace();
            LogUtil.writeLog("银联支付报错：{}" + e);
        }
    }


    @Override
    public void goFrontUrl(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        LogUtil.writeLog("FrontRcvResponse前台接收报文返回开始");

        String encoding = req.getParameter(SDKConstants.param_encoding);
        LogUtil.writeLog("返回报文中encoding=[" + encoding + "]");
        String pageResult = "";
        if (DemoBase.encoding.equalsIgnoreCase(encoding)) {
            pageResult = "/utf8_result.jsp";
        } else {
            pageResult = "/gbk_result.jsp";
        }
        Map<String, String> respParam = getAllRequestParam(req);

        // 打印请求报文
        LogUtil.printRequestLog(respParam);

        Map<String, String> valideData = null;
        StringBuffer page = new StringBuffer();
        if (null != respParam && !respParam.isEmpty()) {
            Iterator<Map.Entry<String, String>> it = respParam.entrySet()
                    .iterator();
            valideData = new HashMap<String, String>(respParam.size());
            while (it.hasNext()) {
                Map.Entry<String, String> e = it.next();
                String key = (String) e.getKey();
                String value = (String) e.getValue();
                value = new String(value.getBytes(encoding), encoding);
                page.append("<tr><td width=\"30%\" align=\"right\">" + key
                        + "(" + key + ")</td><td>" + value + "</td></tr>");
                valideData.put(key, value);
            }
        }
        if (!AcpService.validate(valideData, encoding)) {
            page.append("<tr><td width=\"30%\" align=\"right\">验证签名结果</td><td>失败</td></tr>");
            LogUtil.writeLog("验证签名结果[失败].");
        } else {
            page.append("<tr><td width=\"30%\" align=\"right\">验证签名结果</td><td>成功</td></tr>");
            LogUtil.writeLog("验证签名结果[成功].");
            System.out.println(valideData.get("orderId")); //其他字段也可用类似方式获取

            String respCode = valideData.get("respCode");
            System.out.println("交易状态码-------------：" + respCode);
            if (respCode.equals("00") || respCode.equals("A6")) {
                System.out.println("交易状态吗已确认-----可以更新数据库");
            }
            //判断respCode=00、A6后，对涉及资金类的交易，请再发起查询接口查询，确定交易成功后更新数据库。
        }
        req.setAttribute("result", page.toString());
        req.getRequestDispatcher(pageResult).forward(req, resp);

        LogUtil.writeLog("FrontRcvResponse前台接收报文返回结束");

    }


    //信誉值支付
    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public Response reputationPay(String orderNumber, int i, String source) {
        Response response = new Response();
        Map<String, Object> order;
        if ("1".equals(source)) {
            order = orderDao.getOrderInfoByOrderNumber(orderNumber);
            String customerId = sessionUserUtil.getUserAttr().getCustomerId();
            Customer customer = customerDao.getCustomerById(customerId);
            int newPrice = Integer.parseInt(order.get("realPay").toString());
            //Integer wxAmount = Integer.valueOf((int)(Double.valueOf(amount)*100));
            //判断是否为大客户
            if (customer.getCustomerCategoryId() == 2) {
                if (null != customer) {
                    Integer reputation = customer.getUseReputation();
                    if (reputation < newPrice) {
                        response.setCode(RetCode.PAY_ERROR);
                        return response;
                    }
                    //更改用户信誉值的余额
                    int y = customerDao.updateCustomerReputation(customerId, reputation - newPrice);
                    if (1 == y) {
                        callBack(orderNumber, 5);
                        //保存信誉值记录
                        ReputationHistory reputation1 = new ReputationHistory();
                        reputation1.setCustomerId(customerId);
                        reputation1.setAmount(newPrice);
                        reputation1.setType(0);
                        reputationHistoryDao.insert(reputation1);
                        response.setCode(RetCode.SUCCESS);
                    } else {
                        response.setCode(RetCode.REQUEST_ERROR);
                    }
                } else {
                    log.info("用户A信誉值支付，未找到A，id={}" + customerId);
                    response.setCode(RetCode.REQUEST_ERROR);
                }
            } else {
                response.setCode(RetCode.CUSTOMER_CATEGORY_ERROR_TWO);
            }
        } else {
//            order = orderDao.getOrderInfoByOrderNumber(orderNumber);
            order = demandDao.getDemandInfoByDemandNumber(orderNumber);
            String customerId = sessionUserUtil.getUserAttr().getCustomerId();
            Customer customer = customerDao.getCustomerById(customerId);
            int newPrice = Integer.parseInt(order.get("realPay").toString());
            //Integer wxAmount = Integer.valueOf((int)(Double.valueOf(amount)*100));
            //判断是否为大客户
            if (customer.getCustomerCategoryId() == 2) {
                if (null != customer) {
                    Integer reputation = customer.getUseReputation();
                    if (reputation < newPrice) {
                        response.setCode(RetCode.PAY_ERROR);
                        return response;
                    }
                    //更改用户信誉值的余额
                    int y = customerDao.updateCustomerReputation(customerId, reputation - newPrice);
                    if (1 == y) {
                        callBack(orderNumber, 5);
                        //保存信誉值记录
                        ReputationHistory reputation1 = new ReputationHistory();
                        reputation1.setCustomerId(customerId);
                        reputation1.setAmount(newPrice);
                        reputation1.setType(0);
                        reputationHistoryDao.insert(reputation1);
                        response.setCode(RetCode.SUCCESS);
                    } else {
                        response.setCode(RetCode.REQUEST_ERROR);
                    }
                } else {
                    log.info("用户A信誉值支付，未找到A，id={}" + customerId);
                    response.setCode(RetCode.REQUEST_ERROR);
                }
            } else {
                response.setCode(RetCode.CUSTOMER_CATEGORY_ERROR_TWO);
            }
//            if (null != order) {
//                callBack(orderNumber, 5);
//                response.setCode(RetCode.SUCCESS);
//            } else {
//                response.setCode(RetCode.REQUEST_ERROR);
//            }
        }
        return response;
    }

    //积分换购商品
    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public Response integralRedemption(String integralAmount, String goodsId) {
        Response response = new Response();
        String customerId = sessionUserUtil.getUserAttr().getCustomerId();
        Integer amount = Integer.parseInt(integralAmount);
        Customer customer = customerDao.getCustomerById(customerId);
        if (customer.getCustomerIntegral() >= amount) {
            customer.setCustomerIntegral(customer.getCustomerIntegral() - amount);
            customerDao.updateByPrimaryKey(customer);
            //保存积分记录
            saveCustomerIntegral(1, customerId, 1, amount, goodsId);
            response.setCode(RetCode.SUCCESS);
        } else {
            response.setCode(RetCode.integral_NO);

        }
        return response;
    }

    /**
     * 积分记录
     *
     * @param type：1表示换购商品，2表示购买商品赠送，3表示评论商品赠送
     * @param customerId：用户id
     * @param cutOff：表示商品数量
     * @param amount：表示积分
     * @param goodsId：商品id
     */
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void saveCustomerIntegral(int type, String customerId, int cutOff, Integer amount, String goodsId) {
        CustomerIntegral customerIntegral = new CustomerIntegral();
        customerIntegral.setConsumeType(type);
        customerIntegral.setCreateTime(DateUtils.timeFormat(System.currentTimeMillis()));
        customerIntegral.setCustomerId(customerId);
        customerIntegral.setCutOff(cutOff);
        customerIntegral.setIntegralValue(amount);
        customerIntegral.setGoodsId(goodsId);
        customerDao.saveCustomerIntegral(customerIntegral);
    }

    //支付宝提现
    @Override
    public Response getWithdrawals(Integer money) {
        Response response = new Response();
        if (money != null) {
            Customer customer = sessionUserUtil.getUserAttr();
            if (customer.getCashMoney() > money) {
                 /*调用支付宝接口*/
                AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                model.setBody("支付宝提现");
                model.setSubject("支付宝提现");
                model.setOutTradeNo("");
                model.setTimeoutExpress("30m");
                model.setTotalAmount(String.valueOf(money));
                model.setProductCode("QUICK_MSECURITY_PAY");
                String sign = AliPayUtil.creatSign(model);

                Map<String, String> map = new HashMap<String, String>();
                map.put("out_biz_no", "");
                map.put("payee_type", "ALIPAY_LOGONID");
                map.put("alipayName", customer.getAlipayAccount());
                map.put("amount", String.valueOf(money));
                map.put("payer_show_name", "工老大提现");
                AliPayUtil.invoking(map);

                if (sign != null) {
                    response.setCode(RetCode.SUCCESS);
                } else {
                    response.setCode(RetCode.REQUEST_ERROR);
                }
            } else {
                response.setCode(RetCode.MONEY_LESS);
            }
        } else {
            response.setCode(RetCode.MONEY);
        }
        return response;
    }


    //  信誉值支付 密码验证
    @Override
    public Response verPasswords(String customerId, String password) {
        Response response = new Response();
        Customer customer = customerMapper.selectByPrimaryKey(customerId);
        String password22 = PasswordHelper.encryptPassword(password, customer.getCustomerMobile()); //密码加盐后
        if (!password22.equals(customer.getCustomerPassword())) {
            response.setCode(RetCode.PWD_ERROR);
        } else {
            response.setCode(RetCode.SUCCESS);
        }
        return response;
    }

    //支付成功处理逻辑
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void callBack(String orderNumber, Integer payment) {
        Order order = orderDao.getOrderInfoByOrderNumber22(orderNumber);
        Demand demand = demandDao.getDemandByDemandNumber(orderNumber);
        if (null != demand) {
            if (1 != demandDao.updatePayStatus(orderNumber, payment, DemandStatus.SUCCESS.getStatus())) {
                log.info("订单支付成功逻辑处理失败orderNumber：{}" + orderNumber);
            }
        }
        if (null != order) {
            if (1 != orderDao.updatePaymentAndStatus(orderNumber, payment, OrderStatus.UNDELIVERED.getStatus(), 2)) {
                log.info("订单支付成功逻辑处理失败orderNumber：{}" + orderNumber);
            } else {
                //看订单中的商品是否有赠送积分
                List<Map<String, Object>> sublist = orderDao.getSublist(orderNumber);
                int allIntegral = 0;
                //Order order = orderDao.getOrderInfoByOrderNumber22(orderNumber);
                Customer customer = customerDao.getCustomerById(order.getCustomerId());
                int size01 = sublist.size();
                for (int i = 0; i < size01; i++) {
                    int consumeIntegral = Integer.parseInt(sublist.get(i).get("consumeIntegral").toString());
                    int goodsNumber = Integer.parseInt(sublist.get(i).get("goodsNumber").toString());
                    allIntegral += (consumeIntegral * goodsNumber);
                    //保存积分记录
                    saveCustomerIntegral(2, customer.getCustomerId(), goodsNumber, consumeIntegral, sublist.get(i).get("goodsId").toString());
                }
                customer.setCustomerIntegral(customer.getCustomerIntegral() + allIntegral);
                customerDao.updateByPrimaryKey(customer);

            }

        }
    }


    /**
     * 获取请求参数中所有的信息
     * 当商户上送frontUrl或backUrl地址中带有参数信息的时候，
     * 这种方式会将url地址中的参数读到map中，会导多出来这些信息从而致验签失败，这个时候可以自行修改过滤掉url中的参数或者使用getAllRequestParamStream方法。
     *
     * @param request
     * @return
     */
    public static Map<String, String> getAllRequestParam(final HttpServletRequest request) {
        Map<String, String> res = new HashMap<String, String>();
        Enumeration<?> temp = request.getParameterNames();
        if (null != temp) {
            while (temp.hasMoreElements()) {
                String en = (String) temp.nextElement();
                String value = request.getParameter(en);
                res.put(en, value);
                // 在报文上送时，如果字段的值为空，则不上送<下面的处理为在获取所有参数数据时，判断若值为空，则删除这个字段>
                if (res.get(en) == null || "".equals(res.get(en))) {
                    // System.out.println("======为空的字段名===="+en);
                    res.remove(en);
                }
            }
        }
        return res;
    }

    /**
     * 获取请求参数中所有的信息。
     * 非struts可以改用此方法获取，好处是可以过滤掉request.getParameter方法过滤不掉的url中的参数。
     * struts可能对某些content-type会提前读取参数导致从inputstream读不到信息，所以可能用不了这个方法。理论应该可以调整struts配置使不影响，但请自己去研究。
     * 调用本方法之前不能调用req.getParameter("key");这种方法，否则会导致request取不到输入流。
     *
     * @param request
     * @return
     */
    public static Map<String, String> getAllRequestParamStream(
            final HttpServletRequest request) {
        Map<String, String> res = new HashMap<String, String>();
        try {
            String notifyStr = new String(IOUtils.toByteArray(request.getInputStream()), DemoBase.encoding);
            LogUtil.writeLog("收到通知报文：" + notifyStr);
            String[] kvs = notifyStr.split("&");
            for (String kv : kvs) {
                String[] tmp = kv.split("=");
                if (tmp.length >= 2) {
                    String key = tmp[0];
                    String value = URLDecoder.decode(tmp[1], DemoBase.encoding);
                    res.put(key, value);
                }
            }
        } catch (UnsupportedEncodingException e) {
            LogUtil.writeLog("getAllRequestParamStream.UnsupportedEncodingException error: " + e.getClass() + ":" + e.getMessage());
        } catch (IOException e) {
            LogUtil.writeLog("getAllRequestParamStream.IOException error: " + e.getClass() + ":" + e.getMessage());
        }
        return res;
    }

    /**
     * 验证订单是否填写了地址
     *
     * @param orderNumber
     * @return
     */
    private Response getAddress(String orderNumber) {
        Response response = new Response();
        Map<String, Object> order = orderDao.getOrderInfoByOrderNumber(orderNumber);
        if (null != order && order.size() > 0) {
            if (order.get("addressId").equals("null") || order.get("addressId").toString() == null || order.get("addressId").toString() == "") {
                Map<String, Object> map = new HashMap<>();
                map.put("401", "请填写收货地址");
                response.setData(map);
            }
        } else {
            Map<String, Object> map = new HashMap<>();
            map.put("401", "未找到此订单");
            response.setData(map);
        }
        return response;
    }
}
